
#include "shape.h"
#include <iostream>
using namespace std;

/*-----------------------------------------------------------------------------------------
Name:			Constructor

Description:	Creates dynamic arrays and initializes the shape to 0's

Parameters:		int v: the number of vertices for the shape

Variables:		int vert: the number of vetices
				double x: dynamic array of x values
				double y: dynamic array of y values
				double m: dynamic array of slopes
				double mN: dynamic array of perpendicular (normalized) slopes
				double p: projection points.
					[0] is min x
					[1] is min y
					[2] is max x
					[3] is max y

Return:			none
-----------------------------------------------------------------------------------------*/
Shape::Shape(int v)
{
#if DEBUG
	cout << endl << "*** Constructor" << endl << endl;
#endif

	vert = v;
	x = new double[vert];
	y = new double[vert];
	m = new double[vert];
	mN = new double [vert];
	p = new double[4];
	
	for(int i=0;i<vert;i++)
	{
		setX(i,0);
		setY(i,0);
	}
}

/*-----------------------------------------------------------------------------------------
Name:			Trianble Constructor

Description:	Creates a triangle and initializes it to the parameters, then gets both slopes.

Parameters:		double ax: first vertex x value
				double ay: first vertex y value
				double bx: second vertex x value
				double by: second vertex y value
				double cx: third vertex x value
				double cy: third vertex y value

Variables:		int vert: the number of vetices
				double x: dynamic array of x values
				double y: dynamic array of y values
				double m: dynamic array of slopes
				double mN: dynamic array of perpendicular (normalized) slopes
				double p: projection points.
					[0] is min x
					[1] is min y
					[2] is max x
					[3] is max y

Return:			none
-----------------------------------------------------------------------------------------*/
Shape::Shape(double ax,double ay, double bx,double by,double cx,double cy)
{
#if DEBUG
	cout << endl << "*** Triangle Constructor" << endl << endl;
#endif

	vert = 3;
	x = new double[vert];
	y = new double[vert];
	m = new double[vert];
	mN = new double [vert];
	p = new double[4];
	
	setTri(ax,ay,bx,by,cx,cy);
	setSlope();
	setNormalSlope();
}

/*-----------------------------------------------------------------------------------------
Name:			Destructor

Description:	Deletes dynamic memory

Parameters:		none

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
Shape::~Shape()
{
#if DEBUG
	cout << endl << "*** ~Destructor" << endl << endl;
#endif

	delete [] x;
	delete [] y;
	delete [] m;
	delete [] mN;
	delete [] p;
}

/*-----------------------------------------------------------------------------------------
Name:			setVert

Description:	Sets a specific vertex number to a value

Parameters:		int p: the vertex number to set
				double m: the x value
				double n: the y value

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setVert(int p,double m, double n)
{
	setX(p,m);
	setY(p,n);
}

/*-----------------------------------------------------------------------------------------
Name:			setTri

Description:	Sets values for a triangle

Parameters:		double ax: first vertex x value
				double ay: first vertex y value
				double bx: second vertex x value
				double by: second vertex y value
				double cx: third vertex x value
				double cy: third vertex y value

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setTri(double ax,double ay, double bx,double by,double cx,double cy)
{
	//First Vertex
	setX(0,ax);
	setY(0,ay);

	//Second Vertex
	setX(1,bx);
	setY(1,by);

	//Third Vertex
	setX(2,cx);
	setY(2,cy);
}

/*-----------------------------------------------------------------------------------------
Name:			setX

Description:	Sets the x value for a specific vertex

Parameters:		int p: the vertex number to set
				double m: the x value to set

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setX(int p,double m)
{
	x[p] = m;
}

/*-----------------------------------------------------------------------------------------
Name:			setY

Description:	Sets the y value for a specific vertex

Parameters:		int p: the vertex number to set
				double m: the y value to set

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setY(int p,double n)
{
	y[p] = n;
}

/*-----------------------------------------------------------------------------------------
Name:			setSlope

Description:	Sets the slope for each line in the shape

Parameters:		none

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setSlope()
{
	for(int i=0;i<vert;i++) //for each vertex set the slope
	{
		if(i < vert-1) //if the last vertex is not selected
			m[i] = (y[i+1]-y[i])/(x[i+1]-x[i]);
		else //if the last vertex is selected
			m[i] = (y[0]-y[i])/(x[0]-x[i]);
	}
}

/*-----------------------------------------------------------------------------------------
Name:			setNormalSlope

Description:	Sets the perpendicular (normalized) slope.

Parameters:		none

Variables:		none

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setNormalSlope()
{
	for(int i=0;i<vert;i++) //for each vertex
		mN[i] = -1/m[i]; //invert and negate

}

/*-----------------------------------------------------------------------------------------
Name:			setProjection

Description:	Sets the projected value for a vertex.

Parameters:		int v: the vertex number to project
				double m: pointer to the slope
				double mN: pointer to the normalized slope

Variables:		double xTemp: used to store the projection calculation for the x value
				double yTemp: used to store the projection calculation for the x value

Return:			none
-----------------------------------------------------------------------------------------*/
void Shape::setProjection(int v,double *m_,double *mN_)
{
	double xTemp,yTemp;
	
	//set initial min and max to the first vertex's values
	xTemp = p[0] = p[2] = (y[0]-m_[v]*x[0])/(mN_[v]-m_[v]); //x = (y-mx)/(normal slope - slope)
	yTemp = p[1] = p[3] = mN_[v]*xTemp; //y = mx+b   (b always 0, passing throug origin)

	for(int i=1;i<vert;i++) //cycle through each vertex, starting at the next in line
	{
		xTemp = (y[i]-m_[v]*x[i])/(mN_[v]-m_[v]);
		yTemp = mN_[v]*xTemp;

		if(xTemp < p[0]) //if x value is less than stored min, set new min
		{
			p[0] = xTemp;
			p[1] = yTemp;
		}

		if(xTemp > p[2]) //if x value is greater than stored max, set new max
		{
			p[2] = xTemp;
			p[3] = yTemp;
		}
	}
}

/*-----------------------------------------------------------------------------------------
Name:			getCollision

Description:	Detects whether a collision is detected for each projected min/max

Parameters:		Shape s: a reference to the shape that will be used to test a collision

Variables:		bool collision: true/false whether a collision is detected

Return:			bool collision: true/false whether a collision is detected
-----------------------------------------------------------------------------------------*/
bool Shape::getCollision(Shape &s)
{
	bool collision = true; //assume a collision initially

	for(int i=0;i<vert+s.getVert();i++) //test each vertex in the pair of objects (shape 1's vertices + shape 2's vertices)
	{
		//test if we're checking object 1 or shape 2
		if(i<vert)
		{ //if testing shape 1, send the vertex and slopes of shape 1 to setProjection() for both shapes
			setProjection(i,m,mN);
			s.setProjection(i,m,mN);
		}
		else
		{ //if testing shape 2, start cycling from shape 2's 0 vertex, 
		 //then send the vertex and slopes of shape 2 to setProjection() for both shapes
			setProjection(i-vert,s.getM(),s.getMN());
			s.setProjection(i-vert,s.getM(),s.getMN());
		}

		//once projections have been done, check if you can draw a line between the two points:
		if(p[2] < s.getProjection()[0] || p[0] > s.getProjection()[2])
		{ //if shape 1's max is less than shape 2' min AND shape 1's min is greater than shape 2's max...
			collision = false; //set collision to false
			i=vert+s.getVert(); //kick us out of the loop by setting i to the value needed to prevent entering the loop
		}
	}
	

	return collision;
}